package com.telit.uav.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.telit.common.constant.MsgIdentificationConstants;
import com.telit.common.entity.DataReturn;
import com.telit.common.exception.BaseException;
import com.telit.common.exception.ForestBaseException;
import com.telit.common.response.CommonResultCode;
import com.telit.common.util.HttpClientUtil;
import com.telit.common.util.JwtTokenUtils;
import com.telit.common.util.RandomUtils;
import com.telit.common.util.RedisUtils;
import com.telit.communicate.dto.SendMessageDTO;
import com.telit.communicate.feign.RemoteCommunicateService;
import com.telit.uav.dao.*;
import com.telit.uav.dto.CommUavReportInfoDTO;
import com.telit.uav.dto.UpdateUavLanAndLonDTO;
import com.telit.uav.entity.CommUav;
import com.telit.uav.entity.CommUavModel;
import com.telit.uav.entity.CommUavProducter;
import com.telit.uav.entity.CommUavReportInfo;
import com.telit.uav.service.UavManagerService;
import com.telit.uav.vo.AddUavTokenVO;
import com.telit.uav.vo.UavH5VO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;


/**
 * @author zhouyu
 * @description 无人机管理实现类
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class UavManagerImpl implements UavManagerService {

    @Autowired
    private CommUavDao commUavDao;

    @Autowired
    private RemoteCommunicateService communicateFeignClient;

    @Autowired
    private CommUavReportInfoMapper commUavReportInfoMapper;

    @Autowired
    private UserInfoService userInfoService;


    @Autowired
    private CommUavProducterDao commUavProducterDao;


    @Autowired
    private CommUavModelDao commUavModelDao;

    @Value("${uav.h5.loginUrl}")
    private String h5LoginUrl;

    @Value("${uav.h5.addRTMPPush}")
    private String addRTMPPush;


    @Autowired
    private AppUavTrackDetailDao appUavTrackDetailDao;


    /*
     * 添加无人机厂商
     * */
    @Override
    @Transactional
    public Long addUavDeviceProducter(CommUavProducter commUavProducter) {
        QueryWrapper<CommUavProducter> wrapper = new QueryWrapper<>();

        if (!StringUtils.isEmpty(commUavProducter.getProducter())) {
            wrapper.eq("producter", commUavProducter.getProducter());
        }
        //判断型号是否已经存在
        CommUavProducter oldProducter = commUavProducterDao.selectOne(wrapper);
        if (ObjectUtil.isNotNull(oldProducter)) {
            throw new BaseException(CommonResultCode.DEVICE_PRODUCTER_EXIST, "设备厂商已存在!");
        }
        if (commUavProducterDao.insert(commUavProducter) <= 0) {
            throw new BaseException(CommonResultCode.ERR, "服务器内部错误!");
        }
        return commUavProducter.getId();

    }

    /*
     * 添加无人机型号
     * */
    @Override
    @Transactional
    public Long addUavDeviceModel(CommUavModel commUavModel) {
        QueryWrapper<CommUavModel> wrapper = new QueryWrapper<>();
        wrapper.eq("model", commUavModel.getModel());
        wrapper.eq("producter_id", commUavModel.getProducterId());

        Integer count = commUavModelDao.selectCount(wrapper);
        if (count > 0) {
//            throw new ForestBaseException("设备厂商下已存在相同型号的无人机!");
            throw new BaseException(CommonResultCode.DEVICE_PRODUCTER_EXIST, "设备厂商下已存在相同型号的无人机!");
        }
        //使用默认图片
        if (commUavModel.getIsDefault() == 1) {
            //为默认图片
//            commUavModel.setImageUrl(imagerUrl);
            commUavModel.setImageUrl("[\"forestry/image/firecommand/0bed9eff7b2a340050f882efac521000.jpg\"]");
        }
        if (commUavModelDao.insert(commUavModel) <= 0) {
//            throw new ForestBaseException("无人机型号添加失败");
            throw new BaseException(CommonResultCode.ERR, "服务器内部错误!");
        }
        return commUavModel.getId();
    }


    @Override
    public void deleteUavDeviceModel(Long id) {
        String realName = JwtTokenUtils.getRealName();
        //判断该设备下面是存在无人机
        Integer model = commUavDao.findModel(id.toString());
        if (model != null && model > 0) {
            throw new ForestBaseException("该设备下面存在无人机");
        }

        CommUavModel commUavModel = new CommUavModel();
        commUavModel.setId(id);
        commUavModel.setUpdateTime(new Date());
        commUavModel.setUpdateUser(realName);
        commUavModel.setDeleteTime(new Date());
        commUavModelDao.updateById(commUavModel);
    }


    @Override
    public void changeStatus(String uavCode, Long forestkeeperId, Integer isConnect, String longitude,
                             String latitude) {
        //因为安徽项目目前没有飞手的角色   所以之前的逻辑暂时保留，兼容现在的逻辑
        UpdateUavLanAndLonDTO updateUavLanAndLonDTO = new UpdateUavLanAndLonDTO();
        updateUavLanAndLonDTO.setUavCode(uavCode);
        if (longitude.equals("0.0")||latitude.equals("0.0")){
            //查询最后一次飞行记录的经纬度
            Map<String, String> map = appUavTrackDetailDao.selectLatelyLonAndLatByUavCode(uavCode);
            updateUavLanAndLonDTO.setLongitude(map.get("longitude"));
            updateUavLanAndLonDTO.setLatitude(map.get("latitude"));
        }else {
            updateUavLanAndLonDTO.setLongitude(longitude);
            updateUavLanAndLonDTO.setLatitude(latitude);
        }
        updateUavLanAndLonDTO.setIsConnect(isConnect);
        commUavDao.updateUavLonAndLan(updateUavLanAndLonDTO);
//        commUavDao.changeIsOnLine(uavCode,isConnect);
        if (isConnect == 1) {
            //上线
            commUavDao.deleteStatus(uavCode, forestkeeperId);
            commUavDao.addStatus(uavCode, forestkeeperId, 1);
            SendMessageDTO sendMessageDTO = new SendMessageDTO();
            sendMessageDTO.setFlag("web");
            Map<String, Object> map = new HashMap<>();
            map.put("id", forestkeeperId);
            map.put("status", "1");
            sendMessageDTO.setMsg(JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.USER_UP_DOWN, map)));
            communicateFeignClient.sendMsg(sendMessageDTO);
        } else if (isConnect == 0) {
            //离线删除数据
            //   commUavDao.deleteStatus(uavCode, forestkeeperId);
            SendMessageDTO sendMessageDTO = new SendMessageDTO();
            sendMessageDTO.setFlag("web");
            Map<String, Object> map = new HashMap<>();
            map.put("id", forestkeeperId);
            map.put("status", "2");
            sendMessageDTO.setMsg(JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.USER_UP_DOWN, map)));
            communicateFeignClient.sendMsg(sendMessageDTO);
        }
    }

    @Override
    @Transactional
    public void addUavDevice(CommUav commUav) {
        String uavCode = commUav.getUavCode();
        String uavName = commUav.getUavName();
        Long count = commUavDao.queryByCodeOrName(uavCode, null);
        if (count != 0) {
            throw new ForestBaseException("该无人机编号已存在!");
        }
        count = commUavDao.queryByCodeOrName(null, uavName);
        if (count != 0) {
            throw new ForestBaseException("该无人机名称已存在!");
        }
//        String password="Telit!@157h5";
//        try {
//            password= RSAUtil.privateDecrypt(commUav.getLoginPassWord(), RSAUtil.getDefaultKey().getPrivateKeyStr());
//        }catch (Exception e){
//
//        }
        HashMap<String, String> paramsLogin = new HashMap<>();
        paramsLogin.put("user", commUav.getLoginUser());
        paramsLogin.put("password", commUav.getLoginPassWord());
        //将token补全
        //按照现在的逻辑是将前端公钥加密过后的后端私钥进行解密，拿到用户名密码其请求H5S平台获取session登录，请求insert接口完成token的添加
        //UavH5VO  uavH5VO=h5LoginUrl+"?user="+commUav.getLoginName()+"&password="+ password;
        String strSession = null;
        try {
            String responseStr = HttpClientUtil.doGet(h5LoginUrl, paramsLogin, null);
            UavH5VO uavH5VO = JSON.parseObject(responseStr, UavH5VO.class);
            if (uavH5VO.getBStatus()) {
                strSession = uavH5VO.getStrSession();
            }
        } catch (Exception e) {
            throw new ForestBaseException("h5 获取session失败!");
        }
        //拿到session去添加token
        HashMap<String, String> paramsPushAddToken = new HashMap<>();
        String token = createToken();
        String name = createName(commUav);
        paramsPushAddToken.put("name", name);
        paramsPushAddToken.put("token", token);
        paramsPushAddToken.put("audio", Boolean.toString(false));
        paramsPushAddToken.put("session", strSession);
        AddUavTokenVO addUavTokenVO = new AddUavTokenVO();
        try {
            String responseStr = HttpClientUtil.doGet(addRTMPPush, paramsPushAddToken, null);
            addUavTokenVO = JSON.parseObject(responseStr, AddUavTokenVO.class);
            if (!addUavTokenVO.getBStatus()) {
                throw new ForestBaseException("h5 添加token失败");
            }
        } catch (Exception e) {
            throw new ForestBaseException("h5 调用h5 inset token 失败!");
        }
        //添加token
        commUav.setToken(token);
        //根据行政区划编码查询对应补全数据
        if (!StringUtils.isEmpty(commUav.getDistrictCode())) {
            String province = commUav.getDistrictCode().substring(0, 2);
            commUav.setProvince(province);
            String city = commUav.getDistrictCode().substring(0, 4);
            commUav.setCity(city);
            String county = commUav.getDistrictCode().substring(0, 6);
            commUav.setCounty(county);
        }
        commUav.setCreateTime(new Date());
        commUav.setImageUrl("[\"forestry/image/firecommand/0bed9eff7b2a340050f882efac521000.jpg\"]");
        commUavDao.insertSelective(commUav);
    }

    private String createToken() {
        RandomUtils randomUtils = new RandomUtils(4, ThreadLocalRandom.current());
        return randomUtils.getString();
    }


    private String createName(CommUav commUav) {
        String uavCode = commUav.getUavCode();
        //根据名称和code生成H5平台的name
        return uavCode;
    }


    @Override
    public void deleteById(Long id) {
        commUavDao.deleteByPrimaryKey(id);
    }

    @Override
    public void updateById(CommUav commUav) {
        if (!StringUtils.isEmpty(commUav.getDistrictCode())) {
            String province = commUav.getDistrictCode().substring(0, 2);
            commUav.setProvince(province);
            String city = commUav.getDistrictCode().substring(0, 4);
            commUav.setCity(city);
            String county = commUav.getDistrictCode().substring(0, 6);
            commUav.setCounty(county);
        }
        commUavDao.updateByPrimaryKeySelective(commUav);
    }


    @Override
    public void startOrEndPatrol(String uavCode, String startOrEnd, String trackId) {
        SendMessageDTO sendMessageDTO = new SendMessageDTO();
        sendMessageDTO.setFlag("web");
        Map<String, Object> map = new HashMap<>();
        map.put("uavCode", uavCode);
        map.put("status", startOrEnd);
        sendMessageDTO.setMsg(JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.UAV_PATROL_SIGN, map)));
        communicateFeignClient.sendMsg(sendMessageDTO);
        if ("2".equals(startOrEnd)) {
            RedisUtils.hmPopList(trackId);
        }
    }

    /**
     * app端调用,修改无人机是否飞行中
     *
     * @param uavCode
     * @param isFlying
     */
    @Override
    public void modifyIsFlying(String uavCode, Integer isFlying) {
        commUavDao.updateIsFlying(uavCode, isFlying);
        //推送给web端
        SendMessageDTO sendMessageDTO = new SendMessageDTO();
        sendMessageDTO.setFlag("web");
        Map<String, Object> map = new HashMap<>();
        map.put("uavCode", uavCode);
        map.put("status", isFlying);
        sendMessageDTO.setMsg(JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.UAV_IS_FLYING, map)));

        //推送到前端
        communicateFeignClient.sendMsg(sendMessageDTO);
    }

    /**
     * @description: 根据状态查询无人机列表
     * @author ck
     * @date: 2022/4/23 13:36
     */
    @Override
    public List<CommUav> queryByHealthStatusAndName(Integer healthStatus, String name) {
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------start
        /*List<CommUav> commUavs = commUavDao.queryByHealthStatusAndName(healthStatus, name);
        commUavs.forEach(e -> {
            String uavCode = e.getUavCode();
            Long uav_user_id = commUavDao.queryFlyControllerByCode(uavCode);
            SysUserDetailVo userInfo = userInfoService.getUserInfo(uav_user_id);
            if (userInfo != null) {
                e.setFlyController(userInfo.getRealName());
            }
            String equipmentModelId = e.getEquipmentModel();
            String equipmentModel = commUavDao.queryNameByEquipmentModelId(Long.parseLong(equipmentModelId));
            e.setEquipmentModel(equipmentModel);
            String equipmentManufacturerId = e.getEquipmentManufacturer();
            String equipmentManufacturer = commUavDao.queryNameByEquipmentManufacturerId(Long.parseLong(equipmentManufacturerId));
            e.setEquipmentManufacturer(equipmentManufacturer);
        });
        return commUavs;
        */
        List<CommUav> commUavs = commUavDao.queryByHealthStatusAndName(healthStatus, name);

        commUavs.forEach(e -> {
            String uavCode = e.getUavCode();
            Long uav_user_id = commUavDao.queryFlyControllerByCode(uavCode);
            e.setFlyController(Convert.toStr(uav_user_id));
            String equipmentModelId = e.getEquipmentModel();
            String equipmentModel = commUavDao.queryNameByEquipmentModelId(Long.parseLong(equipmentModelId));
            e.setEquipmentModel(equipmentModel);
            String equipmentManufacturerId = e.getEquipmentManufacturer();
            String equipmentManufacturer = commUavDao.queryNameByEquipmentManufacturerId(
                    Long.parseLong(equipmentManufacturerId));
            e.setEquipmentManufacturer(equipmentManufacturer);
        });
        final Map<Long, String> idNameMapping = Maps.newHashMap();
        if (CollUtil.isNotEmpty(commUavs)) {
            idNameMapping.putAll(userInfoService.findAndConvertUserInfoByIds(
                    commUavs.stream().map(u -> Convert.toLong(u.getFlyController())).collect(Collectors.toList())
            ));
        }
        commUavs.forEach(e -> ObjectUtil.defaultIfNull(
                idNameMapping.get(Convert.toLong(e.getFlyController()))
                , StrUtil.EMPTY)
        );

        return commUavs;
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------end
    }

    @Override
    public IPage<CommUavReportInfo> queryReportList(CommUavReportInfoDTO commUavReportInfoDTO) {
        Date reportBeginTime = commUavReportInfoDTO.getReportBeginTime();
        Date reportEndTime = commUavReportInfoDTO.getReportEndTime();
        String uavName = commUavReportInfoDTO.getUavName();
        Long reporterPersonId = commUavReportInfoDTO.getReporterPersonId();
        QueryWrapper<CommUavReportInfo> queryWrapper = new QueryWrapper<>();

        if (reporterPersonId != null) {
            queryWrapper.le("reporter_person_id", reporterPersonId);
        }
        if (uavName != null && !StringUtils.isEmpty(uavName)) {
            queryWrapper.like("uav_name", uavName);
        }

        if (reportEndTime != null || reportBeginTime != null) {
            queryWrapper.between("report_time", reportBeginTime, reportEndTime);
        }
        IPage<CommUavReportInfo> page = new Page<>(commUavReportInfoDTO.getPage(), commUavReportInfoDTO.getRows());
        queryWrapper.orderByDesc("report_time");
        IPage<CommUavReportInfo> commUavReportInfoIPage = commUavReportInfoMapper.selectPage(page, queryWrapper);
        return commUavReportInfoIPage;
    }


    @Override
    public List<CommUavProducter> findUavDeviceProducter(String producter) {
        QueryWrapper<CommUavProducter> wrapper = new QueryWrapper<>();
        wrapper.like("producter", producter);
        List<CommUavProducter> commUavProducterList = commUavProducterDao.selectList(wrapper);
        return commUavProducterList;
    }

    @Override
    public void updateUavLonAndLan(UpdateUavLanAndLonDTO updateUavLanAndLonDTO) {
        Long count = commUavDao.queryByCodeOrName(updateUavLanAndLonDTO.getUavCode(), null);
        if (count != 0) {
            throw new ForestBaseException("无人机不存在");
        }
        commUavDao.updateUavLonAndLan(updateUavLanAndLonDTO);
    }

}
